package com.youease.chris.view.mediator
{
	import com.youease.chris.control.CreateMapCommand;
	import com.youease.chris.manager.AssetsManager;
	import com.youease.chris.manager.GlobalObject;
	import com.youease.chris.manager.ImageLoader;
	import com.youease.chris.manager.OperateEnum;
	import com.youease.chris.manager.TexturesManager;
	import com.youease.chris.model.proxy.MapDataProxy;
	import com.youease.chris.model.vo.IndexBitmap;
	import com.youease.chris.model.vo.LayerData;
	import com.youease.chris.model.vo.MapData;
	import com.youease.chris.model.vo.TextureData;
	import com.youease.chris.model.vo.TileData;
	import com.youease.chris.view.MapScene;
	import com.youease.chris.view.mediator.MapPropertiesMediator;
	import com.youease.chris.view.mediator.ToolPanelMediator;
	
	import flash.display.Bitmap;
	import flash.events.Event;
	import flash.events.KeyboardEvent;
	import flash.events.MouseEvent;
	import flash.filters.GlowFilter;
	import flash.geom.Point;
	import flash.ui.Keyboard;
	import flash.ui.MouseCursor;
	import flash.utils.Dictionary;
	
	import mx.containers.Canvas;
	import mx.controls.Image;
	import mx.core.UIComponent;
	import mx.managers.CursorManager;
	
	import org.puremvc.as3.interfaces.IMediator;
	import org.puremvc.as3.interfaces.INotification;
	import org.puremvc.as3.patterns.mediator.Mediator;
	
	public class MapSceneMediator extends Mediator implements IMediator
	{
		public static const NAME:String = "MapSceneMediator";
		
		public static const MapSceneMouseMove:String = "MapSceneMouseMove";
		public static const MapSceneMouseWheel:String = "MapSceneMouseWheel";
		public static const MapSceneMouseClick:String = "MapSceneMouseClick";
		public static const MapSceneLoad:String = "MapSceneLoad";
		
		public var layerBitmaps:Dictionary = new Dictionary();
		public var layerUI:Dictionary = new Dictionary();
		public var layerRender:Dictionary = new Dictionary();
		
		private var image:Bitmap = new Bitmap();
		private var imageUI:UIComponent = new UIComponent();
		
		private var mapData:MapData;
		
		public function MapSceneMediator(viewComponent:Object)
		{
			super(NAME, viewComponent);
			mapContainer.addEventListener(MouseEvent.MOUSE_DOWN,onMouseDown);
			mapContainer.addEventListener(MouseEvent.MOUSE_UP,onMouseUp);
			mapContainer.addEventListener(MouseEvent.MOUSE_OUT,onMouseOut);
			mapContainer.addEventListener(MouseEvent.MOUSE_MOVE,onMouseMove);
			mapScene.addEventListener(Event.RESIZE,onResize);
			mapScene.addEventListener(MouseEvent.MOUSE_WHEEL,onMouseWheel);
//			mapScene.addEventListener(MouseEvent.CLICK,onMouseClick);
			mapContainer.addEventListener(MouseEvent.MOUSE_OVER,onMouseOver);
			this.mapContainer.addEventListener(Event.ADDED_TO_STAGE,onAddToStage);
		}
		
		
		
		private function onAddToStage(evt:Event):void {
			this.mapContainer.stage.addEventListener(KeyboardEvent.KEY_DOWN,onHotKey);
			this.mapContainer.stage.addEventListener(KeyboardEvent.KEY_UP,onKeyUp);
			this.mapContainer.removeEventListener(Event.ADDED_TO_STAGE,onAddToStage);
		}
		
		private function onHotKey(evt:KeyboardEvent):void {
			
			switch(evt.keyCode) {
				case Keyboard.S :
					mapContainer.dispatchEvent(new MouseEvent(MouseEvent.MOUSE_OUT));
					mapContainer.dispatchEvent(new MouseEvent(MouseEvent.MOUSE_OVER));
					GlobalObject.currentOperater = OperateEnum.SELECT; 
					break;
				case Keyboard.D :
					mapContainer.dispatchEvent(new MouseEvent(MouseEvent.MOUSE_OUT));
					mapContainer.dispatchEvent(new MouseEvent(MouseEvent.MOUSE_OVER));
					GlobalObject.currentOperater = OperateEnum.DRAG_MAP;
					break;
				case Keyboard.B :
					mapContainer.dispatchEvent(new MouseEvent(MouseEvent.MOUSE_OUT));
					mapContainer.dispatchEvent(new MouseEvent(MouseEvent.MOUSE_OVER));
					GlobalObject.currentOperater = OperateEnum.BRUSH;
					break;
				case Keyboard.F :
					mapContainer.dispatchEvent(new MouseEvent(MouseEvent.MOUSE_OUT));
					mapContainer.dispatchEvent(new MouseEvent(MouseEvent.MOUSE_OVER));
					GlobalObject.currentOperater = OperateEnum.FILL;
					break;
				case Keyboard.E :
					mapContainer.dispatchEvent(new MouseEvent(MouseEvent.MOUSE_OUT));
					mapContainer.dispatchEvent(new MouseEvent(MouseEvent.MOUSE_OVER));
					GlobalObject.currentOperater = OperateEnum.ERASER;
					break;
				case Keyboard.N :
					mapContainer.dispatchEvent(new MouseEvent(MouseEvent.MOUSE_OUT));
					mapContainer.dispatchEvent(new MouseEvent(MouseEvent.MOUSE_OVER));
					GlobalObject.currentOperater = OperateEnum.NOCROSS;
					break;
				case Keyboard.CONTROL:
					GlobalObject.spaceDown = true;
					break;
			}
		}
		
		private function onKeyUp(evt:KeyboardEvent):void {
			if(evt.keyCode == Keyboard.CONTROL) {
				GlobalObject.spaceDown = false;
				mapContainer.stopDrag();
				trace("按下了ctrl。。。。。。。。。。。。。。。。");
			}
			
			if(evt.keyCode == Keyboard.Z && evt.ctrlKey) {
				onHistory();
				trace("回退。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。");
			}
		}
		
		private function onMouseClick(evt:MouseEvent):void {
			var clickGridPoint:Point = coordinateTransform(new Point(evt.localX + mapData.mapCols*mapData.tileWidth/2,evt.localY));
			if(clickGridPoint.x == -1)return;
			var index:int = clickGridPoint.x*mapData.mapCols + clickGridPoint.y;
			clickItem(index);
//			sendNotification(MapSceneMouseClick,evt);
		}
		
		public function onMouseMove(evt:MouseEvent):void {
			GlobalObject.mouseX = Math.floor((evt.localX + mapData.mapCols*mapData.tileWidth/2));
			GlobalObject.mouseY = Math.floor(evt.localY);
			var gridPoint:Point = coordinateTransform(new Point(evt.localX + mapData.mapCols*mapData.tileWidth/2,evt.localY));
			if(gridPoint.x == -1)return;
			GlobalObject.gridX = gridPoint.x;
			GlobalObject.gridY = gridPoint.y;
			
			if(GlobalObject.oldGridX != GlobalObject.gridX||GlobalObject.oldGridY != GlobalObject.gridY) {
				var index:int = GlobalObject.gridX*mapData.mapCols + GlobalObject.gridY;
				var oldIndex:int = GlobalObject.oldGridX*mapData.mapCols + GlobalObject.oldGridY;
				if(evt.buttonDown && GlobalObject.currentOperater!=OperateEnum.BIG_BRUSH) {
					clickItem(index);
				}
				if(GlobalObject.currentOperater!=OperateEnum.DRAG_MAP)
				(layerBitmaps[GlobalObject.currentLayer][index] as Bitmap).filters = [new GlowFilter(0xff0000,1,10,10,2,1,true)];
				(layerBitmaps[GlobalObject.currentLayer][oldIndex] as Bitmap).filters = null;
				
				/*
				if(GlobalObject.currentOperater==OperateEnum.BIG_BRUSH) {
					CursorManager.removeAllCursors();
					this.imageUI.addChild(this.image);
					this.mapContainer.addChild(this.imageUI);
					trace(GlobalObject.projectDir+"/textures/"+GlobalObject.currentBigImag.name);
					ImageLoader.instance.loadImg( GlobalObject.projectDir+"/textures/"+GlobalObject.currentBigImag.name,image,"bitmapData");
					this.imageUI.x = GlobalObject.mouseX;
					this.imageUI.y = GlobalObject.mouseY;
				}else {
					if(this.mapContainer.contains(this.imageUI)) {
						this.mapContainer.removeChild(this.imageUI);
					}
				}*/
			}
			
			//			sendNotification(MapSceneMouseMove,evt);
			if(GlobalObject.oldGridX != GlobalObject.gridX) {
				GlobalObject.oldGridX = GlobalObject.gridX;
			}
			if(GlobalObject.oldGridY != GlobalObject.gridY) {
				GlobalObject.oldGridY = GlobalObject.gridY;
			}
			GlobalObject.canCross = mapData.crossData[GlobalObject.gridX+","+GlobalObject.gridY];
		}
		
		private function clickItem(index:int):void {
			switch(GlobalObject.currentOperater) {
				case OperateEnum.BRUSH: 
					if(GlobalObject.currentTexture)
						changeTexture(index,GlobalObject.currentTexture);
//						layerBitmaps[GlobalObject.currentLayer][index]["bitmapData"] = GlobalObject.currentTexture.bitmapdata;//(new Tile03() as Bitmap).bitmapData;
					break;
				case OperateEnum.FILL:
					if(GlobalObject.currentTexture) {
//						for each(var bitmap:Bitmap in layerBitmaps[GlobalObject.currentLayer]) {
//							bitmap.bitmapData = GlobalObject.currentTexture.bitmapdata;//(new Tile03() as Bitmap).bitmapData;
//						}
						for(var i:int=0;i<mapData.mapRows*mapData.mapCols;i++) {
							changeTexture(i,GlobalObject.currentTexture);
						}
					}
					break;
				case OperateEnum.ERASER:
					changeTexture(index,null);
					break;
				case OperateEnum.NOCROSS:
//					changeTexture(index,null,getTile(index).canCross==1?false:true,true,false);
//					changeCrossData(index);
					break;
				case OperateEnum.BIG_BRUSH:
					var row:int = Math.ceil(GlobalObject.currentBigImag.height/GlobalObject.cellHeight)*2 + 1;
					var col:int = Math.ceil(GlobalObject.currentBigImag.width/GlobalObject.cellWidth) + 1;
					var name:String = GlobalObject.currentBigImag.name.substring(0,GlobalObject.currentBigImag.name.indexOf("."));
					var tempGridX:int = GlobalObject.gridX;
					var tempGridY:int = GlobalObject.gridY;
					for(var r:int=0;r<row;r++) {
						for(var c:int=0;c<col;c++) {
							if(TexturesManager.textures[name+"_"+r+"_"+c+".gif"])
								changeTexture(getIndex(tempGridX,tempGridY),TexturesManager.textures[name+"_"+r+"_"+c+".gif"]);
							tempGridX ++;
							tempGridY ++;
						}
						tempGridX -= col;
						tempGridY -= col;
						if(r%2) {
							tempGridX ++;
						}else {
							tempGridY --;
						}
					}
					break;
			}
			GlobalObject.canCross = mapData.crossData[GlobalObject.gridX+","+GlobalObject.gridY];
		}
		
		private function changeCrossData(index:int):void {
			layerBitmaps[GlobalObject.crossLayerName][index].alpha = mapData.crossData[GlobalObject.gridX+","+GlobalObject.gridY]?.3:0;
			mapData.crossData[GlobalObject.gridX+","+GlobalObject.gridY] = !mapData.crossData[GlobalObject.gridX+","+GlobalObject.gridY];
		}
		
		public function changeTexture(index:int,texture:TextureData,history:Boolean=false):void {
			if(index>=mapData.mapCols*mapData.mapRows) return;
//			trace(GlobalObject.lockLayers[GlobalObject.currentLayer]+"................locked...."+GlobalObject.currentLayer);
			if(GlobalObject.lockLayers[GlobalObject.currentLayer]) return;
			
			var tile:TileData = getTile(index);
			
			if(!history) {
				GlobalObject.pushHistory({gridX:tile.gridX,gridY:tile.gridY,textrue:TexturesManager.textures[tile.textrue.img]});
			}	
			layerBitmaps[GlobalObject.currentLayer][index]["bitmapData"] = texture?texture.bitmapdata:null;
			tile.textrue = texture?texture:new TextureData();
		}
		
		private function onHistory():void {
			var tile:Object = GlobalObject.retriveHistory();
			if(tile) {
				var index:int = tile.gridX*mapData.mapCols + tile.gridY;
				changeTexture(index,tile.textrue,true);
			}
		}
		
		private function getIndex(gridX:int,gridY:int):int {
			var index:int = gridX*mapData.mapCols + gridY;
			return index;
		}
		
		public function getCurrentLayer():LayerData {
			for each(var layerData:LayerData in this.mapData.layers) {
				if(layerData.name == GlobalObject.currentLayer) {
					return layerData;
				}
			}
			return null;
		}
		
		public function getTile(index:int):TileData {
			var cl:LayerData = getCurrentLayer();
			if(cl) {
				return cl.tiles[index];
			}
			return null;
		}
		
		public function onMouseWheel(evt:MouseEvent):void {
			GlobalObject.sceneScale += evt.delta;
			GlobalObject.sceneScale = Math.min(200,GlobalObject.sceneScale);
		}
		
		public function onResize(evt:Event):void {
//			mapContainer.x = mapScene.width/2;
//			mapContainer.y = mapScene.height/2;
		}
		
		public function onMouseDown(evt:MouseEvent):void {
			if(GlobalObject.currentOperater == OperateEnum.DRAG_MAP || GlobalObject.spaceDown) {
				mapContainer.startDrag();
				trace(mapContainer.x+"...............down............."+mapContainer.y);
			}else
				onMouseClick(evt);
		}
		
		public function onMouseUp(evt:MouseEvent):void {
			if(GlobalObject.currentOperater == OperateEnum.DRAG_MAP || GlobalObject.spaceDown) {
				mapContainer.stopDrag();
				
				
				
			}
		}
		
		public function onMouseOver(evt:MouseEvent):void {
			CursorManager.removeAllCursors();
			switch(GlobalObject.currentOperater) {
				case OperateEnum.SELECT:
					CursorManager.setCursor(AssetsManager.cursor_arrow,2,-7,-2);
					break;
				case OperateEnum.DRAG_MAP:
					CursorManager.setCursor( AssetsManager.cursor_drag_hand,2,-16,-16);
					break;
				case OperateEnum.BRUSH:
					CursorManager.setCursor( AssetsManager.brushes,2,-15,-30);
					break;
				case OperateEnum.FILL:
					CursorManager.setCursor( AssetsManager.fill,2,-3,-12);
					break;
				case OperateEnum.RECT_SELECT:
					CursorManager.setCursor( AssetsManager.rectangle,2,-1,-2);
					break;
				case OperateEnum.ERASER:
					CursorManager.setCursor( AssetsManager.eraser,2,-4,-18);
					break;
				case OperateEnum.NOCROSS:
					CursorManager.setCursor( AssetsManager.nocross,2,-16,-16);
			}
		}
		
		public function onMouseOut(evt:MouseEvent):void {
			CursorManager.removeAllCursors();
			onMouseUp(evt);
		}
		
		override public function listNotificationInterests():Array {
			return [
				CreateMapCommand.CREATE_MAP_COMPLETE,
				MapPropertiesMediator.ShowGrid,
				ToolPanelMediator.SHOW_LAYER,
				ToolPanelMediator.LOCK_LAYER,
				MapSceneLoad
			];
		}
		
		override public function handleNotification(notification:INotification):void {
			switch(notification.getName()) {
				case CreateMapCommand.CREATE_MAP_COMPLETE:
					mapData = (notification.getBody() as MapDataProxy).mapData;
					break;
				case MapPropertiesMediator.ShowGrid:
					layerUI["grid"]["visible"] = notification.getBody() as Boolean;
					break;
				case ToolPanelMediator.SHOW_LAYER:
					this.layerUI[notification.getBody()["layerName"]]["visible"] = notification.getBody()["flag"] as Boolean;
					break;
				case ToolPanelMediator.LOCK_LAYER:
//					this.layerUI[notification.getBody()["layerName"]]["visible"] = notification.getBody() as Boolean;
					GlobalObject.lockLayers[notification.getBody()["layerName"]] = notification.getBody()["flag"] as Boolean;
					break;
				case MapSceneLoad:
					load(notification.getBody());
					break;
			}
		}
		
		private function load(obj:Object):void {
			//计算出当前视图的中心点所在网格
//			var offsetX:Number = mapContainer.x - 385;
//			var offsetY:Number = mapContainer.y - 283;
//			
//			var targetX:int = int(mapData.mapCols/2) - int(offsetX/mapData.tileWidth);
//			var targetY:int = int(mapData.mapCols/2) - int(offsetX/mapData.tileWidth);
//			
//			if(Math.abs(offsetX%mapData.tileWidth)>(mapData.tileWidth/2)) {
//				targetX -= offsetX/Math.abs(offsetX);
//				targetY -= offsetX/Math.abs(offsetX);
//			}
//			
//			targetX -= int(offsetY/(mapData.tileWidth/2));
//			targetY += int(offsetY/(mapData.tileWidth/2));
//			
//			if(Math.abs(offsetY%(mapData.tileWidth/2))>(mapData.tileWidth/2)) {
//				targetX -= offsetY/Math.abs(offsetY);
//				targetY += offsetY/Math.abs(offsetY);
//			}
			var targetX:int = int(obj.tx);
			var targetY:int = int(obj.ty);
			
			
			GlobalObject.centerGridX = Math.max(0,Math.min(targetX,mapData.mapRows-1));
			GlobalObject.centerGridY = Math.max(0,Math.min(targetY,mapData.mapRows-1));
			
			var cross:Boolean = false;
			
			for each(var layer:LayerData in mapData.layers) {
				
				var tmpArr:Array = new Array();
				
				for(var gridX:int=Math.max(0,GlobalObject.centerGridX - GlobalObject.rendererRange);gridX<Math.min(mapData.mapRows,GlobalObject.centerGridX + GlobalObject.rendererRange);gridX++) {
					for(var gridY:int=Math.max(0,GlobalObject.centerGridY - GlobalObject.rendererRange);gridY<Math.min(mapData.mapCols,GlobalObject.centerGridY + GlobalObject.rendererRange);gridY++) {
						var ib:IndexBitmap = layerBitmaps[layer.name][gridX*mapData.mapCols + gridY];
						if(!layerUI[layer.name].contains(ib))
							layerUI[layer.name].addChild(ib);
						tmpArr.push(ib);
						tmpArr.sortOn("index",Array.NUMERIC);
						
						if(cross) {
							while(layerRender[GlobalObject.crossLayerName].length>0) {
								layerUI[GlobalObject.crossLayerName].removeChild(layerRender[GlobalObject.crossLayerName].shift());
							}
							var crossIb:Bitmap = layerBitmaps[GlobalObject.crossLayerName][gridX*mapData.mapCols + gridY];
							layerRender[GlobalObject.crossLayerName].push(crossIb);
							layerUI[GlobalObject.crossLayerName].addChild(crossIb);
						}
						
					}
				}
				
				for(var a:int=0;a<tmpArr.length;a++) {
					var add:IndexBitmap = tmpArr[a];
					add.fresh = true;
					if(!layerUI[layer.name].contains(add))
						layerUI[layer.name].addChild(add);
				}
				
				while(layerRender[layer.name].length>0) {
					var old:IndexBitmap = layerRender[layer.name].shift();
					if(!old.fresh) {
						layerUI[layer.name].removeChild(old);
					}
				}
				
				for(var ele:int=0;ele<tmpArr.length;ele++) {
					var sorted:IndexBitmap = tmpArr[ele];
					sorted.fresh = false;
					layerUI[layer.name].setChildIndex(sorted,ele);
				}
				
				layerRender[layer.name] = tmpArr;
				
				cross = false;
			}
		}
		
		/**
		 * 一个菱形，我们都是先画一个正方形，
		 * 然后顺时针旋转45读，之后将y轴缩成原来的1/2。那好，
		 * 逆过来的转化基本就出来了，先将y轴拉升2倍，即y=y*2;然后将坐标逆时针旋转45度，
		 * 坐标旋转公式是
		 * newX = x*cos(θ) - y*sin(θ); newY = x*sin(θ) + y*cos(θ);注意  θ为负45度。x',y'是鼠标点在原来坐标系的坐标
		 * 这样，就转成了平面正角的坐标，不过这时候的新坐标并不是100，而是70.710678，如果要转成100就要乘以1.4142
		 */
		private function coordinateTransform(point:Point):Point {
			//-45度角的弧度值
			var radian45:Number = -Math.PI/4;
			
			var x:Number = point.x;
			var y:Number = point.y*2;
			var newX:Number = x*Math.cos(radian45) - y*Math.sin(radian45);
			var newY:Number =  x*Math.sin(radian45) + y*Math.cos(radian45);
			newX *= 1.4142;
			newY *= 1.4142;
			
			if(newX<0||newX>mapData.tileWidth*mapData.mapRows||
				newY>0||newY<-mapData.tileWidth*mapData.mapCols) {
				return new Point(-1,-1);
			}
			
			var gridX:int = int(newX/mapData.tileWidth);
			var gridY:int = int(newY/mapData.tileWidth);
			gridY = Math.abs(gridY);
			return new Point(gridX,gridY);
		}
		
		public function get mapScene():MapScene {
			return this.viewComponent as MapScene;
		}
		
		public function get mapContainer():Canvas {
			return mapScene.mapContainer;
		}
	}
}